//<<<+++OPENSOURCE
//<<<+++OPENSOURCE_LICENSE
/**
 * @addtogroup FPDFAPI
 * @{
 */

/**
 * @file
 * @brief PDF archiving and serializing.
 */
//<<<+++OPENSOURCE_MUST_BEGIN
#ifndef _FPDF_SERIAL_
#define _FPDF_SERIAL_

#ifndef _FPDF_PAGE_
#include "fpdf_page.h"
#endif

#ifndef _FPDF_PAGEOBJ_H_
#include "fpdf_pageobj.h"
#endif
//<<<+++OPENSOURCE_MUST_END

class CPDF_ObjectStream;
class CPDF_XRefStream;

/**
 * Overloaded operator for serializing a PDF object.
 * Note: only the object itself is serialized (meaning referred objects are not included, if any).
 *
 * @param[out] buf		Ref to the output byte text buffer.
 * @param[in] pObj		The input PDF object.
 * @return The ref to the output byte text buffer.
 */
CFX_ByteTextBuf& operator << (CFX_ByteTextBuf& buf, const CPDF_Object* pObj);

///////////////////////////////////////////////////////////////////////////////////////////////
//
// Basic PDF object archiving facilities.
//	We use an internal binary format for all types of PDF objects.
//
///////////////////////////////////////////////////////////////////////////////////////////////

/** @brief PDF object archive saver class. */
class CPDF_ObjArchiveSaver : public CFX_ArchiveSaver
{
public:
	/**
	 * Save an object to archive.
	 * When an object is stored, all indirect objects referred by it are also stored.
	 * This archive keeps record of previously stored or loaded indirect objects, so they will be 
	 * archived only once to improve performance and reduce memory consumption.
	 * 
	 * It's important to know that certain type of PDF document structures are not suitable
	 * to use this facility, like a page dictionary. A page dictionary refers to a page tree node,
	 * which in turn refers other page tree nodes, and other page dictionaries. So if you use this 
	 * function to archive a page dictionary, essentially all of the PDF document will be archived.
	 *
	 * To solve this problem, the application should break the data structure into pieces, then
	 * archive those necessary pieces one by one.
	 *
	 * @param[out] ar			Ref to output PDF object archive saver.
	 * @param[in] pObj			The input PDF object.
	 * @return The ref to the output PDF object archive saver.
	 */
	friend CPDF_ObjArchiveSaver&	operator << (CPDF_ObjArchiveSaver& ar, const CPDF_Object* pObj);

protected:
	/** map of indirect objects. */
	CFX_MapPtrToPtr			m_ObjectMap;
};

/** @brief PDF object archive loader class. */
class CPDF_ObjArchiveLoader : public CFX_ArchiveLoader
{
public:
	/**
	 * Construct a loading archive.
	 *
	 * @param[in] pData			The input memory block.
	 * @param[in] dwSize		The size of the input memory block.
	 */
	CPDF_ObjArchiveLoader(FX_LPCBYTE pData, FX_DWORD dwSize) : CFX_ArchiveLoader(pData, dwSize),
		m_IndirectObjects(NULL) {}

	/**
	 * Load an object from archive.
	 * 
	 * The loaded object may have reference to indirect objects. When you add the loaded object
	 * to a document, it's important to import as external object.
	 *
	 * @param[in] ar			Ref to the input object archive loader.
	 * @param[out] pObj			It receives the loaded PDF object.
	 * @return The ref to the input object archive loader.
	 */
	friend CPDF_ObjArchiveLoader&	operator >> (CPDF_ObjArchiveLoader& ar, CPDF_Object*& pObj);

protected:
	/** Indirect objects. */
	CPDF_IndirectObjects		m_IndirectObjects;
};

///////////////////////////////////////////////////////////////////////////////////////////////
//
// PDF page object archiving facilities.
//
///////////////////////////////////////////////////////////////////////////////////////////////

/** @brief PDF page archive saver class. */
class CPDF_PageArchiveSaver : public CPDF_ObjArchiveSaver
{
public:
	/**
	 * Construct a saving archive.
	 *
	 * @param[in] pPageObjs		The input page object list.
	 */
	CPDF_PageArchiveSaver(CPDF_PageObjects* pPageObjs);

	/**
	 * Save page object.
	 *
	 * @param[out] ar			Ref to the output page archive saver.
	 * @param[in] pObj			The input page object.
	 * @return The ref to the output page archive saver.
	 */
	friend CPDF_PageArchiveSaver&	operator << (CPDF_PageArchiveSaver& ar, CPDF_PageObject* pObj);

	/**
	 * @name Save graphic states.
	 */
	/*@{*/

	/**
	 * Save clipping path.
	 *
	 * @param[out] ar			Ref to the output page archive saver.
	 * @param[in] clip_path		The input clipping path.
	 * @return The ref to the output page archive saver.
	 */
	friend CPDF_PageArchiveSaver&	operator << (CPDF_PageArchiveSaver& ar, CPDF_ClipPath clip_path);
	/**
	 * Save graph state.
	 *
	 * @param[out] ar			Ref to the output page archive saver.
	 * @param[in] graph_state	The input graph state.
	 * @return The ref to the output page archive saver.
	 */
	friend CPDF_PageArchiveSaver&	operator << (CPDF_PageArchiveSaver& ar, CPDF_GraphState graph_state);
	/**
	 * Save text state.
	 *
	 * @param[out] ar			Ref to the output page archive saver.
	 * @param[in] text_state	The input text state.
	 * @return The ref to the output page archive saver.
	 */
	friend CPDF_PageArchiveSaver&	operator << (CPDF_PageArchiveSaver& ar, CPDF_TextState text_state);
	/**
	 * Save color state.
	 *
	 * @param[out] ar			Ref to the output page archive saver.
	 * @param[in] color_state	The input color state.
	 * @return The ref to the output page archive saver.
	 */
	friend CPDF_PageArchiveSaver&	operator << (CPDF_PageArchiveSaver& ar, CPDF_ColorState color_state);
	/**
	 * Save general state.
	 *
	 * @param[out] ar				Ref to the output page archive saver.
	 * @param[in] general_state	The input general state.
	 * @return The ref to the output page archive saver.
	 */
	friend CPDF_PageArchiveSaver&	operator << (CPDF_PageArchiveSaver& ar, CPDF_GeneralState general_state);

	/*@}*/

protected:
	/** The last clipping path. */
	CPDF_ClipPath		m_LastClipPath;
	/** The last graph state. */
	CPDF_GraphState		m_LastGraphState;
	/** The last color state. */
	CPDF_ColorState		m_LastColorState;
	/** The last text state. */
	CPDF_TextState		m_LastTextState;
	/** The last general state. */
	CPDF_GeneralState	m_LastGeneralState;
	/** The current page objects list. */
	CPDF_PageObjects*	m_pCurPage;
};

/** @brief PDF page archive loader class. */
class CPDF_PageArchiveLoader : public CPDF_ObjArchiveLoader
{
public:
	/**
	 * Construct a loading archive.
	 *
	 * @param[in] pPageObjs			The current page/form.
	 * @param[in] pData				The input memory buffer.
	 * @param[in] dwSize			The size of the input buffer.
	 */
	CPDF_PageArchiveLoader(CPDF_PageObjects* pPageObjs, FX_LPCBYTE pData, FX_DWORD dwSize);

	/**
	 * Load or restore a page object.
	 *
	 * @param[in] ar				Ref to the input page archive loader.
	 * @param[out] pObj				It receives the loaded page object.
	 * @return The ref to the input page archive loader.
	 */
	friend CPDF_PageArchiveLoader&	operator >> (CPDF_PageArchiveLoader& ar, CPDF_PageObject*& pObj);

	/**
	 * @name Load or restore graphic states.
	 */
	/*@{*/

	/**
	 * Load or restore the clipping path.
	 *
	 * @param[in] ar				Ref to the input page archive loader.
	 * @param[out] clip_path		It receives the clipping path.
	 * @return The ref to the input page archive loader.
	 */
	friend CPDF_PageArchiveLoader&	operator >> (CPDF_PageArchiveLoader& ar, CPDF_ClipPath& clip_path);
	/**
	 * Load or restore the graph state.
	 *
	 * @param[in] ar				Ref to the input page archive loader.
	 * @param[out] graph_state		It receives the graph state.
	 * @return The ref to the input page archive loader.
	 */
	friend CPDF_PageArchiveLoader&	operator >> (CPDF_PageArchiveLoader& ar, CPDF_GraphState& graph_state);
	/**
	 * Load or restore the text state.
	 *
	 * @param[in] ar				Ref to the input page archive loader.
	 * @param[out] text_state		It receives the text state.
	 * @return The ref to the input page archive loader.
	 */
	friend CPDF_PageArchiveLoader&	operator >> (CPDF_PageArchiveLoader& ar, CPDF_TextState& text_state);
	/**
	 * Load or restore the color state.
	 *
	 * @param[in] ar				Ref to the input page archive loader.
	 * @param[out] color_state		It receives the color state.
	 * @return The ref to the input page archive loader.
	 */
	friend CPDF_PageArchiveLoader&	operator >> (CPDF_PageArchiveLoader& ar, CPDF_ColorState& color_state);
	/**
	 * Load or restore the general state.
	 *
	 * @param[in] ar				Ref to the input page archive loader.
	 * @param[out] general_state	It receives the general state.
	 * @return The ref to the input page archive loader.
	 */
	friend CPDF_PageArchiveLoader&	operator >> (CPDF_PageArchiveLoader& ar, CPDF_GeneralState& general_state);

	/*@}*/

protected:
	void				PostProcColor(CPDF_Color& color);
	/**
	 * Add a resource.
	 * 
	 * @param[in] pSrcObj		The input PDF object.
	 * @param[in] type			The resource type name.
	 */
	CPDF_Object*		AddResource(CPDF_Object* pSrcObj, FX_LPCSTR type);

	/** The las clipping path. */
	CPDF_ClipPath		m_LastClipPath;
	/** The last graph state. */
	CPDF_GraphState		m_LastGraphState;
	/** The last color state. */
	CPDF_ColorState		m_LastColorState;
	/** The last text state. */
	CPDF_TextState		m_LastTextState;
	/** The last general state. */
	CPDF_GeneralState	m_LastGeneralState;
	/** The current page object list. */
	CPDF_PageObjects*	m_pCurPage;
	/** Object mapping. */
	CFX_MapPtrToPtr		m_ObjectMap;
};

//*****************************************************************************
//* PDF Creator
//*****************************************************************************
/**
 * @name Creating flags for PDF creator.
 */
/*@{*/

/** @brief Incremental. */
#define FPDFCREATE_INCREMENTAL		1
/** @brief No original. */
#define FPDFCREATE_NO_ORIGINAL		2
/** @brief Use progressive creator. */
#define FPDFCREATE_PROGRESSIVE		4
/** @brief Use object stream creator. */
#define FPDFCREATE_OBJECTSTREAM		8

/*@}*/

//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
class CPDF_CreatorOption : public CFX_Object
{
public:
	virtual ~CPDF_CreatorOption() {}

	virtual IFX_FileStream*		GetTempFile(CPDF_Object* pObj) = 0;
	virtual void				ReleaseTempFile(IFX_FileStream* pFile) = 0;
};

//<<<+++OPENSOURCE_END
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT||LIC==GOOGLE
/** @brief PDF Creator: creating PDF file from a document object. */
class CPDF_Creator : public CFX_Object
{
public:
	/** Construct with a PDF document. */
	CPDF_Creator(CPDF_Document* pDoc);
	/** The destructor. */
	~CPDF_Creator();

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Set data compression. By default, CPDF_Creator use Flate compression for all data streams in release mode,
	 * but not in debug mode.
	 *
	 * @param[in] bEnable		Whether to do data compressing.
	 */
	void				Compress(FX_BOOL bEnable) { m_bCompress = bEnable; }
	
	/**
	 * Encrypt file attachment, but not other streams and string. 
	 *
	 * @param[in] bEnable		Whether to encrypt file attachments only.
	 */
	void				EncryptAttachmentsOnly(FX_BOOL bEnable) { m_bEFFOnly = bEnable; }
	
	/**
	 * Add attachment stream object number.
	 *
	 * @param[in] objnum		The attachment stream number.
	 */
	void				AddAttachments(const CFX_DWordArray& attachs);

	/**
	 * Set security settings using standard security handler only.
	 * Can't be used with incremental update.
	 *
	 * @param[in] permissions			The user permissions.
	 * @param[in] user_pass				The user password.
	 * @param[in] user_pass_len			The length of user password.
	 * @param[in] owner_pass			The owner password.
	 * @param[in] owner_pass_len		The length of owner password.
	 * @param[in] cipher				The cipher type, RC4 or AES.
	 * @param[in] key_bytes				The length of the document key.
	 * @param[in] bEncryptMetadata		Whether to encrypt the metadata.
	 */
	void				SetStandardSecurity(FX_DWORD permissions, FX_LPCBYTE user_pass, int user_pass_len,
								FX_LPCBYTE owner_pass, int owner_pass_len, int cipher, int key_bytes,
								FX_BOOL bEncryptMetadata);

	/**
	 * Modify security permissions for Revision 5 and 6 handler (AES 256)
	 * @param[in] bPermissions		Whether permission and EncryptMetadata changed.
	 * @param[in] permissions		New permissions value.
	 * @param[in] bEncryptMetadata	New EncryptMetadata value.
	 * @param[in] bUserPassword		Whether user password changed (owner password required).
	 * @param[in] user_pass			The user password pointer.
	 * @param[in] user_size			The length of the user password.
	 * @param[in] bOwnerPassword	Whether owner password changed.
	 * @param[in] owner_pass		The owner password pointer.
	 * @param[in] owner_size		The length of the owner password.
	 */
	void				ModifyAES256Security(FX_BOOL bPermissions, FX_DWORD permissions, FX_BOOL bEncryptMetadata,
								FX_BOOL bUserPassword, FX_LPCBYTE user_pass, FX_DWORD user_size, 
								FX_BOOL bOwnerPassword, FX_LPCBYTE owner_pass, FX_DWORD owner_size);
	/**
	 * Set security using custom security handler and custom encryption.
	 * Application should provide a full encryption dictionary (application can destroy it after this call),
	 * and a custom encryption handler.
	 *
	 * @param[in] pEncryptDict			The Encrypt dictionary.
	 * @param[in] pCryptoHandler		The crypto handler.
	 * @param[in] bEncryptMetadata		Whether to encrypt the metadata.
	 */
	void				SetCustomSecurity(CPDF_Dictionary* pEncryptDict, CPDF_CryptoHandler* pCryptoHandler,
								FX_BOOL bEncryptMetadata);
	//<<<+++OPENSOURCE_END
	/**
	 * Remove security settings. The output file will not be encrypted.
	 * Can't be used with incremental update.
	 */
	void				RemoveSecurity();

	/**
	 * Write the whole document into a new file (using Unicode file name). Unicode version.
	 *
	 * @param[in] filename	The output filename(The length must less than 256).
	 * @param[in] flags		The creating flags.
	 * @return Non-zero means success, otherwise failed.
	 */
	FX_BOOL				Create(FX_LPCWSTR filename, FX_DWORD flags = 0);

	/**
	 * Write the whole document into a new file (using local file name). Local version.
	 *
	 * @param[in] filename	The output filename(The length must less than 256).
	 * @param[in] flags		The creating flags.
	 * @return Non-zero means success, otherwise failed.
	 */
	FX_BOOL				Create(FX_LPCSTR filename, FX_DWORD flags = 0);

	/** 
	 * Write the whole document to a custom file access.
	 *
	 * @param[out] pFile	The output file access.
	 * @param[in] flags		The creating flags.
	 * @return Non-zero means success, otherwise failure.
	 */
	FX_BOOL				Create(IFX_StreamWrite* pFile, FX_DWORD flags = 0);

	/** 
	 * Continue to write document data under progressive mode.
	 *
	 * @param[in] pPause	Pause object, optional.
	 * @return	Negative value if failure, 0 if finishes, and positive value if need to be continued.
	 * @remark	Only valid if pass FPDFCREATE_PROGRESSIVE flag in calling Create method.
	 */
	FX_INT32			Continue(IFX_Pause *pPause = NULL);

    //<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * @name Get object offset and size in to newly created file. Valid only if Create() function succeeded. 
	 * If the object with specific number doesn't exist, the returned value will be zero.
	 * If incremental update is used, offsets and sizes are only valid for modified indirect objects.
	 */
	/*@{*/ 

	/** Get object offset. */
	FX_FILESIZE			GetObjectOffset(FX_DWORD objnum);
	/** Get object size. */
	FX_DWORD			GetObjectSize(FX_DWORD objnum);

	/*@}*/

	/**
	 * Set object stream size, the default size is 200.
	 *
	 * @param[in] size	The size of object stream.
	 */
	void				SetObjectStreamSize(FX_INT32 size = 200);
	//<<<+++OPENSOURCE_END

	/**
	 * Set file version. It should be from 10 to 17.
	 *
	 * @param[in] size	The file version.
	 *
	 * @return It will return false if the file Version is out of range.
	 */
	FX_BOOL				SetFileVersion(FX_INT32 fileVersion = 17);

	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/**
	 * Set Progressive Encrypt Handler if need.
	 * EncryptAttachmentsOnly must be call first if want to encrypt attachments only.
	 */
	void				SetProgressiveEncryptHandler(CPDF_ProgressiveEncryptHandler* pHandler);

	void				SetCreatorOption(CPDF_CreatorOption* pOption);
    //<<<+++OPENSOURCE_END
    
protected:
	/** The PDF document. */
	CPDF_Document*		m_pDocument;
	/** The PDF parser. */
	CPDF_Parser*		m_pParser;
	/** Whether to do compressing. */
	FX_BOOL				m_bCompress;

	/** Whether the security has been changed. */
	FX_BOOL				m_bSecurityChanged;
	/** The Encrypt dictionary. */
	CPDF_Dictionary*	m_pEncryptDict;
	FX_DWORD			m_dwEnryptObjNum;
	FX_BOOL				m_bEncryptCloned;
	/** Whether it use the standard security or not. */
	FX_BOOL				m_bStandardSecurity;
	/** The crypto handler. */
	CPDF_CryptoHandler*	m_pCryptoHandler;
	FX_BOOL				m_bNewCrypto;
	/** Whether to encrypt the metadata. */
	FX_BOOL				m_bEncryptMetadata;
	/** The Metadata. */
	CPDF_Object*		m_pMetadata;
	/** The XRef Stream. */
	CPDF_XRefStream*	m_pXRefStream;
	/** The Object Stream Size. */
	FX_INT32			m_ObjectStreamSize;
	/** The last object number */
	FX_DWORD			m_dwLastObjNum;

	FX_BOOL				Create(FX_DWORD flags);

	void				ResetStandardSecurity();
	void				Clear();
	FX_INT32			WriteDoc_Stage1(IFX_Pause *pPause);
	FX_INT32			WriteDoc_Stage2(IFX_Pause *pPause);
	FX_INT32			WriteDoc_Stage3(IFX_Pause *pPause);
	FX_INT32			WriteDoc_Stage4(IFX_Pause *pPause);

	/** The output file write interface. */
	CFX_FileBufferArchive	m_File;
	/** The current offset. */
	FX_FILESIZE			m_Offset;

	void				InitOldObjNumOffsets();
	void				InitNewObjNumOffsets();
	void				AppendNewObjNum(FX_DWORD objbum);

	FX_INT32			WriteOldIndirectObject(FX_DWORD objnum);
	FX_INT32			WriteOldObjs(IFX_Pause *pPause);
	FX_INT32			WriteNewObjs(FX_BOOL bIncremental, IFX_Pause *pPause);
	FX_INT32			WriteIndirectObj(const CPDF_Object* pObj);
	FX_INT32			WriteDirectObj(FX_DWORD objnum, const CPDF_Object* pObj, FX_BOOL bEncrypt = TRUE);

	FX_INT32			WriteIndirectObjectToStream(const CPDF_Object* pObj);
	FX_INT32			WriteIndirectObj(FX_DWORD objnum, const CPDF_Object* pObj);
	FX_INT32			WriteIndirectObjectToStream(FX_DWORD objnum, FX_LPCBYTE pBuffer, FX_DWORD dwSize);
	FX_INT32			AppendObjectNumberToXRef(FX_DWORD objnum);
	void				InitID(FX_BOOL bDefault = TRUE);

	FX_INT32			WriteStream(const CPDF_Object* pStream, FX_DWORD objnum, CPDF_CryptoHandler* pCrypto);
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	FX_INT32			WriteStream(const CPDF_Object* pStream, FX_DWORD objnum);
	FX_INT32			WriteStreamWithOption(const CPDF_Object* pStream, FX_DWORD objnum);
	//<<<+++OPENSOURCE_END
	/** Progressive data. */
	FX_INT32			m_iStage;
	FX_DWORD			m_dwFlags;
	FX_POSITION			m_Pos;
	FX_FILESIZE			m_XrefStart;

	/** The object offset array. */
	CFX_FileSizeListArray	m_ObjectOffset;
	/** The object size array. */
	CFX_DWordListArray		m_ObjectSize;
	CFX_DWordArray		m_NewObjNumArray;
	/** The ID array. */
	CPDF_Array*			m_pIDArray;
	/** file version. */
	FX_INT32			m_FileVersion;
	//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
	/** Encrypt file attachments only. */
	FX_BOOL				m_bEFFOnly;
	/** The Object number array of attachments stream. */
	CFX_DWordArray		m_Attachments;

	CPDF_ProgressiveEncryptHandler*	m_pProgressiveEncrypt;
	CPDF_CreatorOption*	m_pOption;
	//<<<+++OPENSOURCE_END
	friend class CPDF_ObjectStream;
	friend class CPDF_XRefStream;
};
//<<<+++OPENSOURCE_END
//<<<+++OPENSOURCE_BEGIN LIC==FOXIT
//*****************************************************************************
//* PDF Wrapper
//* Refer to "FSI2011004 PDF Wrapper" standardization.
//*****************************************************************************
/** @brief PDF wrapper creator. */
class IPDF_WrapperCreator
{
public:
	/**
	 * Release the current instance.
	 */
	virtual void		Release() = 0;

	/**
	 * Set wrapper data.
	 *
	 * @param[in] bsType			Wrapper type name.
	 * @param[in] iVersion			Wrapper version.
	 * @param[in] bsApplication		Application identity which indicates how to process the current wrapper file.
	 * @param[in] bsURI				a URI site to retrieve more helpful information if necessary.
	 * @param[in] bsDescription		Description text for application.
	 */
	virtual void		SetWrapperData(FX_BSTR bsType, FX_INT32 iVersion, FX_BSTR bsApplication, FX_BSTR bsURI, FX_BSTR bsDescription) = 0;

	/**
	 * Set security settings using standard security handler only.
	 * Can't be used with incremental update.
	 *
	 * @param[in] permissions			The user permissions.
	 * @param[in] owner_pass			The owner password.
	 * @param[in] owner_pass_len		The length of owner password.
	 */
	virtual void		SetStandardSecurity(FX_DWORD permissions, FX_LPCBYTE owner_pass, int owner_pass_len) = 0;

	/** 
	 * Write the wrapper version to a custom file access.
	 *
	 * @param[out] pFile	The output file access.
	 * @return Non-zero means success, otherwise failure.
	 */
	virtual FX_BOOL		Create(IFX_StreamWrite* pFile) = 0;
};

/**
 * @brief Create an instance of IPDF_WrapperCreator.
 *
 * @param[in] pWrapperDoc		A document object which defines wrapper version, caller maintains its life-time.
 * @param[in] dwWrapperOffset	Offset in bytes from the beginning of PDF file, for wrapper version.
 *
 * @return An instance of interface IPDF_WrapperCreator, NULL pointer if error happens.
 */
IPDF_WrapperCreator*	FPDF_WrapperCreator_Create(CPDF_Document* pWrapperDoc, FX_DWORD dwWrapperOffset);

//*****************************************************************************
//* PDF Linearization
//*****************************************************************************
/** @brief	Linearization flags. */
#define FPDF_LINEARIZATION_Outlines		0x01	//need outline objects, not used currently.

/** @brief PDF linearization creator. */
class IPDF_Linearization
{
public:
	/**
	 * @brief	Release the current instance.
	 */
	virtual void		Release() = 0;

	/**
	 * @brief	Analyze and linearize PDF document, this method should be called before Create method.
	 *
	 * @return	If this method returns FALSE, means error occurs, do not call Create again. TRUE for successful linearization.
	 */
	virtual FX_BOOL		Linearize() = 0;

	/**
	 * Set security using custom security handler and custom encryption.
	 * Application should provide a full encryption dictionary (application can destroy it after this call),
	 * and a custom encryption handler.
	 *
	 * @param[in] pEncryptDict			The Encrypt dictionary.
	 * @param[in] pCryptoHandler		The crypto handler.
	 * @param[in] bEncryptMetadata		Whether to encrypt the metadata.
	 */
	virtual void		SetCustomSecurity(CPDF_Dictionary* pEncryptDict, CPDF_CryptoHandler* pCryptoHandler) = 0;

	/**
	 * Write the wrapper version to a custom file access.
	 *
	 * @param[out] pFile	The output file access.
	 * @return	Negative value if failure, otherwise finishes successfully.
	 */
	virtual FX_INT32	Create(IFX_StreamWrite* pFile) = 0;
};
/**
 * @brief	Create an instance of PDF Linearization.
 *
 * @param[in] pDocument		the document object to be linearized.
 * @param[in] dwFlags		flags indicate how to linearize PDF document, refer to FPDF_LINEARIZATION_XXX macros.
 *
 * @return An instance of interface IPDF_Linearization, NULL pointer if error happens.
 */
IPDF_Linearization* IPDF_Linearization_Create(CPDF_Document *pDocument, FX_DWORD dwFlags = 0);

//*****************************************************************************
//* Page/Form content generator
//*****************************************************************************
/** @brief PDF content generator. */
class CPDF_ContentGenerator
{
public:
	/** Construct with a page. */
	CPDF_ContentGenerator(CPDF_Page* pPage);
	/** Construct with a form. */
	CPDF_ContentGenerator(CPDF_Form* pForm);
	/** The destructor. */
	~CPDF_ContentGenerator();

	/** Replace the page/form content stream. */
	void				GenerateContent();
	/** Replace the page/form content stream by file. */
	void				GenerateContent(IFX_FileStream* pFileStream);
	/**
	 * Get content stream in a text buffer.
	 *
	 * @param[out] cbArContent		It receives the content stream.		
	 */
	void				GenerateContent(CFX_ByteTextBuf & cbArContent);

protected:
    void ProcessText(CFX_ByteTextBuf & cbArText,CPDF_TextObject * pTextObj);
	void ProcessPath(CFX_ByteTextBuf & cbArPath,CPDF_PathObject * pPathObj);
	void ProcessImage(CFX_ByteTextBuf & cbArImage,CPDF_ImageObject * pImageObj);
	void ProcessShading(CFX_ByteTextBuf & cbArImage,CPDF_ShadingObject * pShadingObj);
	void ProcessForm(CFX_ByteTextBuf & cbArImage,CPDF_FormObject * pFormObj);
	void ProcessInlineImage(CFX_ByteTextBuf & cbArImage,CPDF_ImageObject * pImageObj);
	void AbbrInlineImageDict(CPDF_Dictionary *pImageDict);
	void ProcessInlineImageDict(CPDF_Dictionary *pDict);
	void OutputObject(CFX_ByteTextBuf& str, CPDF_Object *pObj);
	void OutputEncodeInlineImage(CFX_ByteTextBuf& str, CPDF_ImageObject *pImageObj);

	void ProcessClip(CFX_ByteTextBuf & cbArContent, CPDF_ClipPath ClipPath);
	void ProcessTextState(CFX_ByteTextBuf & cbArContent, CPDF_PageObject* pPageObj, FX_BOOL bClipText);
	void ProcessGraphState(CFX_ByteTextBuf & cbArContent, CPDF_GraphState GraphState);
	void ProcessColorState(CFX_ByteTextBuf & cbArContent, CPDF_ColorState ColorState);
	void ProcessGeneralState(CFX_ByteTextBuf & cbArContent, CPDF_GeneralState GeneralState);
	void ProcessContentMark(CFX_ByteTextBuf & cbArContent, CPDF_ContentMark Mark);

	void ProcessSingleObject(CFX_ByteTextBuf& byteArray, CPDF_PageObject* pPageObj, FX_BOOL bClipText);
	void BeginText(CFX_ByteTextBuf& cbArContent);
	void OutputPath(CFX_ByteTextBuf& str, CPDF_Path path);

	CFX_ByteString FindExtGS(CPDF_GeneralState LastState, CPDF_GeneralState State);

	void ResetLastStates();

	FX_BOOL				Initialize();

	CPDF_PageObjects*	m_pObjList;
	IFX_FileStream*		m_pFileStream;
	FX_FILESIZE			m_nStartOffset;
	FX_BOOL				m_bForm;
	int					m_nCurrObjectType;

	// Current graphic states. NULL means unknown
	CPDF_ClipPath		m_LastClipPath;
	CPDF_GraphState		m_LastGraphState;
	CPDF_TextState		m_LastTextState;
	CPDF_GeneralState	m_LastGeneralState;
	CPDF_ColorState		m_LastColorState;
	CPDF_ContentMark	m_LastContentMark;

	// Current text position 
	FX_FLOAT			m_dbOffsetPosX;
	FX_FLOAT			m_dbOffsetPosY;

	FX_BOOL				m_bInitialized;
};
//<<<+++OPENSOURCE_END

//<<<+++OPENSOURCE_MUST_BEGIN
#endif
//<<<+++OPENSOURCE_MUST_END

/** @} */
